import base64
import pickle
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from django_redis import get_redis_connection
from .serializers import CartSerializer, CartSKUSerializer,CartDeleteSerializer,CartSelectedAllSerializer
from rest_framework import status
from rest_framework.response import Response
from . import constants
from goods.models import SKU

# Create your views here.


class CartView(APIView):

    def perform_authentication(self, request):
        """
        校验是否登录
        :param request:
        :return:
        """
        pass

    def post(self, request):
        """添加购物车"""
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 取出校验后的数据
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')

        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            user = None
        #  is_authenticated校验用户是否认证通过
        if user and user.is_authenticated:
            # 把商品添加redis

            '''
            sku_id, count, selected
            '''
            conn = get_redis_connection('cart')
            pl = conn.pipeline()

            # 保存的是商品的数量
            pl.hincrby('cart_%s'%user.id, sku_id, count)
            # 勾选状态
            if selected:
                pl.sadd('selected_cart_%s'%user.id, selected)
            pl.execute()

            # 返回
            return Response(serializer.validated_data, status=status.HTTP_201_CREATED)

        else:
            # 用户未登录，保存到cookie
            cart = request.COOKIES.get('cart')

            if cart:
                #  说明之前添加过，只要吧商品数量进行累加
                '''
                sku_id: {
                    'count': 10,
                    'selected':True
                }
                '''
                cart = pickle.loads(base64.b64decode(cart.encode()))

            else:
                # 重新添加
                cart = {}

            # 取出商品, 原来有添加过购物车
            sku = cart.get('sku_id')
            if sku:
                # 取出原有商品的数量
                cookie_count = cart['sku_id']['count']
                # 对商品进行累加
                count += int(cookie_count)

            # 第一次把商品添加到购物车， 添加到cookie
            cart[sku_id] = {
                'count': count,
                'selected': selected
            }

            # 把dict转化为strx写入coookie
            cookie_str = base64.b64encode(pickle.dumps(cart)).decode()
            response = Response(serializer.validated_data, status=status.HTTP_201_CREATED)
            response.set_cookie('cart', cookie_str, max_age=constants.CART_COOKIE_EXPIRES)
            return response

    def get(self, request):
        """查询购物车"""

        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            user = None

        # is_authenticated校验用户是否认证通过
        if user and user.is_authenticated:
            # 登录就查询redis, 把商品数量及是否勾选及商品id取来
            conn = get_redis_connection('cart')
            # 取出商品的数量, sku_id
            redis_cart = conn.hgetall('cart_%s' % user.id)
            # 取出是否勾选
            redis_cart_selected = conn.smembers('selected_cart_%s'%user.id)

            # 用于保存商品的id以及商品的数量和勾选状态
            cart = {}
            for sku_id, count in redis_cart.items():
                cart[int(sku_id)] = {
                    'count':count,
                    # 展示的商品要被勾选
                    'selected': sku_id in redis_cart_selected
                }
        else:

            # 从cookie中取来
            cart = request.COOKIES.get('cart')
            if cart is not None:
                # 取出已经添加的商品，进行解码转化为dict
                cart = pickle.loads(base64.b64decode(cart.encode()))
            else:
                cart = {}

        # 输出购物车数据
        # 取出购物车中商品的信息
        skus = SKU.objects.filter(id__in = cart.keys())
        for sku in skus:
            # 取出购物车的商品数量重新给商品数量赋值
            sku.count = cart[sku.id]['count']
            # 取出购物车商品的勾选状态新给商品状态赋值
            sku.selected = cart[sku.id]['selected']
        #  把购物车数据进行序列化输出
        ser = CartSKUSerializer(skus, many=True)

        return Response(ser.data, status=status.HTTP_200_OK)

    def put(self, request):
        # 获取前端来的数据进行校验
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 取出校验后的数据
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')
        #  判断是否登录
        try:
            user = request.user
        except Exception:
            user = None
            #  is_authenticated校验用户是否认证通过
        if user and user.is_authenticated:
            # 登录的修改redis中当前商品的数据信息
            # 修改cookie中当前商品的数据
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            pl.hset('cart_%s' % user.id, sku_id, count)
            if selected:
                pl.sadd('cart_selected_%s' % user.id, sku_id)
            else:
                pl.srem('cart_selected_%s' % user.id, sku_id)
            pl.execute()
            return Response(serializer.data)

        else:
            # 用户未登录，保存到cookie
            cart = request.COOKIES.get('cart')
            if cart is not None:
                cart = pickle.loads(base64.b64decode(cart.encode()))
            else:
                cart = {}

            # 修改cookie中商品的信息
            cart[sku_id] = {
                'count': count,
                'selected': selected
            }
            cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()

            response = Response(serializer.data)
            # 设置购物车的cookie
            # 需要设置有效期，否则是临时cookie
            response.set_cookie('cart', cookie_cart, max_age=constants.CART_COOKIE_EXPIRES)
            return response

    def delete(self, request):
        """删除购物车商品"""
        # 获取前端来的数据进行校验， 校验商品是否存在
        serializer = CartDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 取出校验后的数据
        sku_id = serializer.validated_data.get('sku_id')
        # 判断是否登录
        #  判断是否登录
        try:
            user = request.user
        except Exception:
            user = None

        # redis中删除商品
        # cookie中删除该商品
        if user is not None and user.is_authenticated:
            # 用户已登录，在redis中保存
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            pl.hdel('cart_%s' % user.id, sku_id)
            pl.srem('cart_selected_%s' % user.id, sku_id)
            pl.execute()
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            # 用户未登录，在cookie中保存
            response = Response(status=status.HTTP_204_NO_CONTENT)

            # 使用pickle序列化购物车数据，pickle操作的是bytes类型
            cart = request.COOKIES.get('cart')
            if cart is not None:
                # 取出cookie中商品的信息进行解码,dict
                cart = pickle.loads(base64.b64decode(cart.encode()))
                if sku_id in cart:
                    # 删除关于该商品的信息
                    del cart[sku_id]
                    # 把字典转化为base64的str
                    cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                    # 设置购物车的cookie
                    # 需要设置有效期，否则是临时cookie
                    response.set_cookie('cart', cookie_cart, max_age=constants.CART_COOKIE_EXPIRES)
            return response


class CartSelectedALLView(APIView):
    """商品全选"""
    def perform_authentication(self, request):
        """校验是否登录"""

    def put(self, request):
        # 获取前端是否全选的状态, 在序列化中校验
        serializer = CartSelectedAllSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data['selected']
        # 判断是否登录
        #  判断是否登录
        try:
            user = request.user
        except Exception:
            user = None

        if user is not None and user.is_authenticated:
            # 登录的修改redis中所有商品的状态信息
            redis_conn = get_redis_connection('cart')
            # 取出所有的商品的id
            cart = redis_conn.hgetall('cart_%s' % user.id)
            # 取出所有的商品的id
            sku_id_list = cart.keys()
            if selected:
                # 添加所有勾选的商品
                # 全选
                redis_conn.sadd('cart_selected_%s' % user.id, *sku_id_list)
            else:
                # 一处所有为勾选的商品
                # 全选
                redis_conn.srem('cart_selected_%s' % user.id, *sku_id_list)
            return Response({'message':'ok'})
        else:
            # 没有登录就修改cookie中所有的状态信息
            # 取出cookie的信息
            # 使用pickle序列化购物车数据，pickle操作的是bytes类型
            cart = request.COOKIES.get('cart')

            response = Response({'message':'ok'})

            if cart:
                cart = pickle.loads(base64.b64decode(cart.encode()))
                for sku_id in cart:
                    # 把全部商品设置为勾选的状态
                    cart[sku_id]['selected'] = selected
                cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                # 设置购物车的cookie
                # 需要设置有效期，否则是临时cookie
                response.set_cookie('cart', cookie_cart, max_age=constants.CART_COOKIE_EXPIRES)

            return response

